package edu.ecu.seng6270.goa.ropa;

import java.util.ArrayList;
import java.util.Iterator;

import edu.ecu.seng6270.goa.pss.PSSExternal;

/**
 * Order Class -- Primary model / business logic class representing a single order. 
 */
public class Order {

	private Boolean isExpress = false;
	private Boolean promoEligible = false;
	private String  promoCode;
	private String 	userID = "";
	
	private Double  nonDiscountedPrice = 0.0;
	private Double  volumeDiscount = 0.0;
	private Double  discountedPrice = 0.0;
	private Double  promoDiscount = 2.0;
	
	ArrayList<OrderItem> myItemList;
	
	/**
	 * Basic constructor
	 * @param userID
	 */
	public Order (String userID) {
		this.userID = userID;
		this.myItemList = new ArrayList<OrderItem>();
	}

	
	/**
	 * Returns the JSON form of the Order
	 * in a String;
	 * 
	 * @return
	 */
	public String serialzeToJSON() {
		return PSSExternal.serializeOrderToJSON(this);
	}
	
	
	/**
	 * Method to add an OrderItem into this Order
	 * 
	 * @param oi
	 * @return
	 */
	public Boolean insertOrderItem (OrderItem oi) {
		
		if (oi.validateOrderItem()) {
			if (isExpress) {
				if (myItemList.size() == 0) {
					myItemList.add(oi);
					return true;
				}
			} else {
				myItemList.add(oi);
				return true;
			}
		}
		return false;
	}
	
	
	/**
	 * Checks if order is valid and complete but
	 * does not consider promo codes.
	 * 
	 * @return
	 */
	public Boolean validateOrder() {
		
		// We must have a userID
		if (userID == null) {return false;}

		// If Express, exactly one item, otherwise 1 or more
		if (isExpress) {
			if (myItemList.size() != 1) {
				return false;
			}
		} else {
			if (myItemList.size() < 1) {
				return false;
			}
		}
		
		int totalQuantity = 0;
		
		// All items must be valid
		for (OrderItem oi : myItemList) {
			if (!oi.validateOrderItem()) {
				return false;
			}
			totalQuantity += oi.getMyQuantity();
		}
		
		// Max order quantity is 100
		if (totalQuantity > 100) {return false;}
		
		return true;
	}
	
	/**
	 * Method to determine if provided promoCode is
	 * valid.  If so, stores it in the Order instance
	 * 
	 * @return
	 */
	public Boolean validatePromoCode(String promoCode) {
		if (promoCode == null) {
			return false;
		}
		
		if (!promoCode.equals("N56M2")) {
			this.promoCode = null;
			return false;
		}
		
		this.promoCode = promoCode;
		return true;
	}
	
	
	/**
	 * Method calculates the total price of the order
	 * exclusive of promotional codes.
	 * 
	 * No Return Value: updates instance fields -- Negative on Error
	 * 
	 */
	public void calculateOrderPrice() {
		OrderItem oi;
		Double subtotal = 0.0;
		Integer quantity = 0;
		
		int soso, good, best = 0;
		
		if (this.validateOrder()) {
			if (isExpress) {
				oi = myItemList.get(0);
				if (oi != null) {
					
					quantity = oi.getMyQuantity();
					
					// In an express order, all characteristics are same
					// so promo eligibility is strictly determined by
					// quantity being equal to 100 (max)
					this.promoEligible = (quantity == 100) ? true : false; 
				
					////////////////////////////////////////////////////////
					// Bucket the quantities -- Consider this CAREFULLY!!!
					// This is the KEY BOUNDARY logic; if this logic is wrong,
					// everything else will be wrong!!
					////////////////////////////////////////////////////////
					soso = (quantity > 50) ? 50 : quantity;
					best = (quantity > 75) ? quantity - 75 : 0;
					good = quantity - (soso + best);
										
					/////////////////////////////////////////////////////////
					// If we bucketed correctly, the rest is just math based
					// based on the size of of the photo.
					/////////////////////////////////////////////////////////
					switch (oi.getMySize()) {
						case 1:
							subtotal += (soso * 0.14);
							subtotal += (good * 0.12);
							subtotal += (best * 0.10);
							if (oi.getMyFinish() == 2) {subtotal += quantity * 0.02;} // Extra for Matte
							break;
						case 2:
							subtotal += (soso * 0.34);
							subtotal += (good * 0.31);
							subtotal += (best * 0.28);
							if (oi.getMyFinish() == 2) {subtotal += quantity * 0.03;} // Extra for Matte
							break;
						case 3:
							subtotal += (soso * 0.68);
							subtotal += (good * 0.64);
							subtotal += (best * 0.60);
							if (oi.getMyFinish() == 2) {subtotal += quantity * 0.04;} // Extra for Matte
							break;
					}
					
					// Upcharge for 1-Hour Processing if any
					if (oi.getMyPTime() == 2) {
						subtotal += (quantity <= 60) ? 1 : 1.5;
					}
					
					this.nonDiscountedPrice = subtotal;
					
					if (subtotal > 35) {
						this.volumeDiscount = subtotal * 0.05;
					} else {
						this.volumeDiscount = 0.0;
					}
					
					if (promoCode != null && promoEligible && volumeDiscount < promoDiscount) {
						this.volumeDiscount = promoDiscount;
					}
					
					this.discountedPrice = this.nonDiscountedPrice - this.volumeDiscount;
					return;
				}
				
			} else {
				
				// added by pouyan
				
				
				int totnumofprint = 0; //This value is used to see how many prints are in this order 
				boolean processingtime = false; // If it is fals then the processing would be set for next day 
				Iterator<OrderItem> itr = myItemList.iterator();
				while(itr.hasNext())
				{
					oi = itr.next();
					quantity = oi.getMyQuantity();
		
					switch (oi.getMySize()) {
						case 1:
							subtotal += quantity * 0.19;
							if(oi.getMyFinish() == 2) { subtotal += quantity * 0.04 ;}  // Extra for Matte
							break;
						case 2:
							subtotal += quantity * 0.39;
							if(oi.getMyFinish() == 2) { subtotal += quantity * 0.06 ;}  // Extra for Matte
							break;
						case 3:
							subtotal += quantity * 0.79;
							if(oi.getMyFinish() == 2) { subtotal += quantity * 0.08 ;}  // Extra for Matte
							break;
					}
					// Upcharge for 1-Hour Processing if any
					if (oi.getMyPTime() == 2) {
						processingtime = true; 
					}
					//To have the total number of prints
					totnumofprint += quantity; 
				}
					
				// Upcharge for 1-Hour Processing if any
				if (processingtime) {
					subtotal += (totnumofprint <= 60) ? 2 : 2.5;
				}
				
				this.nonDiscountedPrice = subtotal;
				
				if (subtotal > 35) {
					this.volumeDiscount = subtotal * 0.05;
				} else {
					this.volumeDiscount = 0.0;
				}
				
				this.discountedPrice = this.nonDiscountedPrice - this.volumeDiscount;
				return;
				
				//end of things added by Pouyan
			}
			
		} //ENDIF ValidateOrder
		
		// IF WE GET HERE, THERE WAS AN ERROR
		this.nonDiscountedPrice = -1.0;
	}
	//////////////////////////
	////Order Item Check////
	////By Pouyan///////////
	///////////////////////
	public OrderItem CheckDuplicate(OrderItem oi)
	{
		OrderItem oitemp;
		Iterator<OrderItem> itr = myItemList.iterator();
		while(itr.hasNext())
		{
			oitemp = itr.next();
			if( oi.getMyFinish() == oitemp.getMyFinish() && oi.getMyPTime() == oitemp.getMyPTime() && oi.getMySize() == oitemp.getMySize()
					&& oi.getMyPhotoId() == oitemp.getMyPhotoId())
			{
				return oitemp;
			}
				
		}
		return null;
	}
	
	
	////End of COde by Pouyan///
	
	
	//////////////////////////
	// Getters and Setters	//
	//////////////////////////
	
	
	public String getUserID() {
		return userID;
	}

	public void setUserID(String userID) {
		this.userID = userID;
	}

	public Boolean getIsExpress() {
		return isExpress;
	}

	public void setIsExpress(Boolean isExpress) {
		this.isExpress = isExpress;
	}

	public Boolean getPromoEligible() {
		return promoEligible;
	}

	public void setPromoEligible(Boolean promoEligible) {
		this.promoEligible = promoEligible;
	}

	public String getPromoCode() {
		return promoCode;
	}

	public ArrayList<OrderItem> getMyItemList() {
		return myItemList;
	}


	public Double getNonDiscountedPrice() {
		return nonDiscountedPrice;
	}


	public Double getDiscountedPrice() {
		return discountedPrice;
	}


	public Double getVolumeDiscount() {
		return volumeDiscount;
	}


}
